#include <iostream>
#include <unistd.h>
#include <sstream>
#include <utils/event_waiter_frame/event_waiter_frame.hpp>
#include <autoinit.hpp>
#include <boost/thread.hpp>
#include <elog.h>
#include <assert.h>
#include <inputmanager.hpp>


using namespace std;


// UTF-8


/*
int* p = para
pfunc(* p);

void* p = para
pfunc(* p);
*/

static const int len = 2;

void event_waiter::event_waiter_register_func_part_up(pfunc pfunc,  event_waiter_para* para)
{
    int func_addr    = reinterpret_cast<int>(pfunc);
    func_parts[0]    = func_addr;

    int para_addr    = reinterpret_cast<int>(para);
    func_parts.at(1) = para_addr;
}

void event_waiter::event_waiter_register_func_part_down(pfunc pfunc,  event_waiter_para* para)
{
    int func_addr    = reinterpret_cast<int>(pfunc);
    func_parts[2]    = func_addr;

    int para_addr    = reinterpret_cast<int>(para);
    func_parts[3]    = para_addr;

    #if 0
        event_waiter_para* p = reinterpret_cast<event_waiter_para*>(func_parts[3]);
        cout << "p = " << hex << p << endl;

        cout << "func_parts[3] = " << hex << func_parts[3] << endl;
    #endif
}

void event_waiter::event_waiter_register_cancel_funcpartdown(pfunc pfunc,  event_waiter_para* para)
{
    int func_addr    = reinterpret_cast<int>(pfunc);
    func_parts[4]    = func_addr;

    int para_addr    = reinterpret_cast<int>(para);
    func_parts[5]    = para_addr;
}


int event_waiter::i_mq_name = 0;

int event_waiter::wait_event(int& r_event_t){ // 等待消息队列，取出事件类型

        unsigned int priority;  
        message_queue::size_type recvd_size;  
        int event_t_recv;  
        p_mq_event->receive(&event_t_recv, sizeof(int), recvd_size, priority); 
        if(recvd_size != sizeof(int)) {
            std::cout << "wait_event(): false " << std::endl;
            assert(0);
            return false;  

        }else{
            r_event_t = event_t_recv;
            log_d("wait_event(): event_t_recv = %d \n", event_t_recv);
           
            return true;  
        }
}    


int event_waiter::wait_resource(int* resource_t, int* cancel_reason){
        unsigned int priority;  
        message_queue::size_type recvd_size;  
        int resource_t_recv[len] = {0};  
        p_mq_resource->receive(resource_t_recv, len*sizeof(int), recvd_size, priority); 
        if(recvd_size != len*sizeof(int)) {
            
            assert(0);
            return false;  

        }else{
            *resource_t    = resource_t_recv[0];
            *cancel_reason = resource_t_recv[1];

            return true;  
        }
    return 0;
}   

event_waiter::event_waiter(int state): step(state){

      i_mq_name++;
      stringstream ss;
      ss << i_mq_name;

      string tmp1 = ss.str();

      string tmp2("mq_event_");
      mq_event = tmp2+tmp1;

      string tmp3("mq_resource_");
      mq_resource = tmp3+tmp1;

      std::cout << mq_event << "  " << mq_resource << std::endl;

  try{
      //Erase previous message queue   
      message_queue::remove(mq_event.c_str());  
      //Create a message_queue.   
      message_queue mq1  
        (create_only,               //only create   
         mq_event.c_str() ,         //name   
         2,                        //max message number   
         sizeof(int)                //max message size   
         ); 

  }catch(interprocess_exception &ex){ 
    
    message_queue::remove(mq_event.c_str());  
    std::cout << ex.what() << std::endl;     
    assert(0);
 
    return;  
   }          
    /* 下面是定义栈变量，函数退出，栈对象销毁，类似智能指针原理，会导致之前打开的消息队列也被关闭。
     为什么说类似智能指针原理，因为栈对象是栈对象，而消息队列是消息队列(应该是分配在堆空间上)，这是两个东西，占用不同的内存，
      这里仅仅是通过一个栈对象，来关联了一个消息队列而已。该栈对象mq的析够，会导致消息队列所占堆内存的析够。
    message_queue mq
         (open_only       
         ,"message_queue"  
         );
    */
     p_mq_event =  new  message_queue       //Open a message queue.    
                        (open_only,
                        mq_event.c_str()     //name   
                        ); 


  try{
      message_queue::remove(mq_resource.c_str()); 
      //Create a message_queue.   
      message_queue mq2  
        (create_only,       //only create   
         mq_resource.c_str() ,      //name   
         10,                        //max message number   
         len*sizeof(int)                //max message size   
         ); 


  }catch(interprocess_exception &ex){  

    message_queue::remove(mq_resource.c_str()); 
    std::cout << ex.what() << std::endl;  
    assert(0);
    
    return;  
   }  

     p_mq_resource = new message_queue       //Open a message queue.    
                        (open_only,
                        mq_resource.c_str()    //name   
                        ); 
}


void event_waiter::do_event_loop_thread(){

    log_d("do_event_loop_thread ......."); 
    while(1)
    {
        switch(step) 
        {
            case s_start_init:
            {
                // 资源初始化
                
                step = s_waitevent; 
                break;
            }

            case s_waitevent:
            {
                log_i("s_waitevent ......."); 
                wait_event(p_realtime_para_partdown);       // 等待外部调用wake_event()方法

                //log_d("wait_event(): p_para->status = %d \n",    \
                            reinterpret_cast<input_dev_param*>(p_realtime_para_partdown)->status);
               
                step = s_dofunc_part_up;
                break;
            }

            case s_dofunc_part_up:  // 执行事件的上半部: 
            {
                // 在这里添加事件的上半部的处理函数
                // ...
                cout << "step = s_dofunc_part_up" << endl;
                    // 可选方案：
                    // 借助信号与槽机制，将事件的上半部的处理函数作为槽函数，在此处维护一个信号或其引用？
                pfunc p_func;  
                int p_func_addr =func_parts[0];

                if(p_func_addr != 0){
                    p_func = reinterpret_cast<pfunc>(p_func_addr); 

                    event_waiter_para *p_para;
                    int p_func_para =func_parts[1];

                    #if 0 
                        p_para = reinterpret_cast<event_waiter_para*>(p_func_para);  //使用默认的注册参数
                    #else
                    p_para = reinterpret_cast<event_waiter_para*>(p_realtime_para_partdown); //使用实时传入的参数
                    #endif

                    p_func(p_para); 
                }

                step = s_wait_resource; 
                break;
            }   
                    
            case s_wait_resource: 
            {
                int resource_t = 0, cancel_reason = 0;
             
                log_w("step = s_wait_resource ... \n"); 
                
                // 等待外部调用wake_resource()方法   
                wait_resource(&resource_t, &cancel_reason);

                if(resource_t == t_resource_for_funcpartdown_gotready){
                    step = s_dofunc_part_down; 

                    log_i("step = s_dofunc_part_down \n"); 
                }
                else if(resource_t == t_cancel_funcpartdown){  

                    p_realtime_para_cancelpartdown = cancel_reason;
                    log_i("step = t_cancel_funcpartdown \n"); 

                    pfunc p_func_do_cancel;  
                    int p_func_addr =func_parts[4];

                    if(p_func_addr != 0){
                        p_func_do_cancel = reinterpret_cast<pfunc>(p_func_addr); 

                        event_waiter_para *p_para;
                        int p_func_para =func_parts[5];
                        p_para = reinterpret_cast<event_waiter_para*>(p_func_para); 

                        if(p_para != NULL){
                            // 取消执行下半部： 预先注册的默认参数
                            p_func_do_cancel(p_para);

                        }else{
                            // 取消执行下半部：
                            event_waiter_para* ppara = reinterpret_cast<event_waiter_para*>(p_realtime_para_cancelpartdown);
                            p_func_do_cancel(ppara); 
                            // 这里的设计上还需要新增一个参数，存入p_realtime_para_partdown
                            // 即存入 之前发起事件上半部时的传入参数。
                            // 例如，注册的时候，会传入参数，取消注册的时候，也该使用此参数，填上外部实时传入的取消原因
                        }
                    }
                    step = s_waitevent;  
                }

                break;
            }
            case s_dofunc_part_down: // 执行事件的下半部
            {
            // 在这里添加事件的下半部的处理函数
            // ...
                    pfunc p_func;  
                    int p_func_addr =func_parts[2];

                    if(p_func_addr != 0){
                        p_func = reinterpret_cast<pfunc>(p_func_addr); 

                        event_waiter_para *p_para;
                        int p_func_para =func_parts[3];
                        p_para = reinterpret_cast<event_waiter_para*>(p_func_para); 
                    
                        if(p_para != NULL){

                            // 如果默认注册的参数
                            p_func(p_para);

                        }else{
                            
                            // 如果默认未传入参数，则使用实时传入的参数
                            p_func(reinterpret_cast<event_waiter_para*>(p_realtime_para_partdown));
                        }
                    }

                    // 事件的下半部分完成以后，重新回到等待下一轮事件的状态。
                    step = s_waitevent; 
                break;
            }  

            default:
                cout << "#ERR: s_null" << endl;
                boost::this_thread::sleep(boost::posix_time::seconds(1));
                break;
        }
    }
}


void event_waiter::create_event_loop(){

    // 这里应该执行获取消息队列中的消息(可以是，事件类型 或 纯数据，或者兼有)，
    // 然后执行对应的事件，事件进行异步处理(单独放在一个线程)
    // 比如：获取到事件类型，然后执行状态机的对应动作。event_invoke(EVENT_STOP) 这种。
    boost::thread t(boost::bind(&event_waiter::do_event_loop_thread, this));
    t.detach();   
}


void event_waiter::wake_event(int event_t){
 
    p_mq_event->send(&event_t, sizeof(event_t), 0);  
}

void event_waiter::wake_resource(int* resource_t){
    //唤醒资源的同时，可以传递消息。以便唤醒资源后执行不同的操作。
    p_mq_resource->send(resource_t, len*sizeof(int), 0);  
}


void event_waiter::wake_resource(void){       // 执行当前事件的下半部
    int* resource_t = new int[len];
    resource_t[0]   = t_resource_for_funcpartdown_gotready;
    resource_t[1]   = 0;

    wake_resource(resource_t);
    delete [] resource_t;
}

void event_waiter::cancel_funcpartdown(int cancel_reason){ // 取消执行当前事件的下半部

    int* resource_t = new int[len];
    resource_t[0]   = t_cancel_funcpartdown;
    resource_t[1]   = cancel_reason;

    wake_resource(resource_t);
    delete [] resource_t;
}


#if 0 // test
#include <autoinit.hpp>

void func_action1(event_waiter_para*p){

    int* paddr = reinterpret_cast<int*>(p->para);
    cout << "func_action1,  p : "     << p << endl;
    cout << "func_action1,  paddr : " << paddr << " ,  " << p->para << endl;
    cout << "func_action1,  data : "  << dec << *paddr << endl;
}

void func_cancel_action(event_waiter_para*p){
    cout << "cancel -- cancel"  << endl;
}

event_waiter obj(s_start_init);

static void test(){
    int dat1_int_t = 888;   
              cout << "&dat1_int_t = " << &dat1_int_t << endl;
    event_waiter_para data1;
    data1.para = &dat1_int_t;
             cout << "&data1 = " << &data1 << endl;
             cout << "data1.para = " << data1.para << endl << endl;
    obj.event_waiter_register_func_part_up(func_action1,   &data1);

    int dat2_int_t = 666; 
              cout << "&dat2_int_t = " << &dat2_int_t << endl;
    event_waiter_para data2;
    data2.para = &dat2_int_t;
             cout << "&data2 = "  << &data2 << endl;    
             cout << "data2.para = " << data2.para << endl;
    obj.event_waiter_register_func_part_down(func_action1, &data2);

    obj.event_waiter_register_cancel_funcpartdown(func_cancel_action, NULL);

    obj.create_event_loop();

    sleep(1);
    int event_t = 99;
    obj.wake_event(event_t);

    sleep(1);
    //obj.wake_resource();
    obj.cancel_funcpartdown();                                


    sleep(6);
}
#endif


#if 0 // Segmentation fault
      // 当本函数退出时，局部对象obj被销毁，
      // 而其成员函数do_event_loop_thread仍然作为线程方法在运转，会造成运行崩溃：Segmentation fault
    static void test(){
        cout << "test() " << endl;

        event_waiter obj(s_start_init);
        obj.create_event_loop();

        sleep(1);
        int event_t = 100;
        obj.wake_event(event_t);
    }


#endif

//auto_dev_init(test);

